﻿using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if UNITY_2019_1_OR_NEWER
using Unity.Collections.LowLevel.Unsafe;
#endif
namespace USArray
{
    public struct StringNoGC
    {
        public static readonly StringHeader strHeaderDef;
        static StringNoGC()
        {
            unsafe
            {
                var defObj = new string('_', 1);
                GCHandle.Alloc(defObj);//死Pin 一个对象，以免参考对象没了，不一定有啥意义
                strHeaderDef = *UnsafePtrTool.GetStringHeader(defObj);
            }
        }
        int maxlen;
        bool nofree;//不要执行free
        unsafe StringHeader* ptr;

        public int Length
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                unsafe
                {
                    return ptr == null ? 0 : ptr->length;
                }
            }
        }

        //边界检查太多，性能就差
        public char this[int i]
        {
            get
            {
                unsafe
                {
                    if (i < 0 || i >= Length)
                    {
                        throw new IndexOutOfRangeException();
                    }
                    return CharPtr[i];
                }
            }
            set
            {
                unsafe
                {
                    if (i < 0 || i >= Length)
                    {
                        throw new IndexOutOfRangeException();
                    }
                    CharPtr[i] = value; ;
                }
            }
        }
        public void ResetLength(int len)
        {
            if (len < 0 || len > MaxLength)
                throw new IndexOutOfRangeException();
            unsafe
            {
                ptr->length = len;
            }
        }
        public int MaxLength
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return maxlen;
            }
        }

        public unsafe StringHeader* HeadPtr
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return ptr;
            }
        }
        public unsafe char* CharPtr
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                if (ptr == null)
                    throw new Exception("String NOGC is null.");
                return (char*)(ptr + 1);
            }
        }

        public bool IsTemp
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                return nofree;
            }
        }
        //临时分配的String,不用管，Unity每帧回收，无GC
        //持久化分配的就是malloc 分配，
        private StringNoGC(int _maxlen, bool _nofree = true, bool _withclear = false)
        {
            maxlen = _maxlen;
            nofree = _nofree;
            unsafe
            {
                var size = sizeof(ArrayHeader) + _maxlen * 2;
                ptr = (StringHeader*)UnsafePtrTool.Malloc(size, _nofree);

                if (_withclear)

                    UnsafeUtility.MemClear(ptr, size);
                ptr[0] = strHeaderDef;
                ptr->length = 0;
            }
        }
        public static StringNoGC Create(int _maxlen, bool _nofree = true, bool _withclear = false)
        {
            return new StringNoGC(_maxlen, _nofree, _withclear);
        }
        //从string 创建一个StringNoGC，可以控制他的长度
        unsafe private StringNoGC(ref string str)
        {
            maxlen = str.Length;
            nofree = true;
            ptr = UnsafePtrTool.GetStringHeader(str);
        }
        //不要用常量初始化，修改常量影响的是整个程序
        public static StringNoGC ConnectTo(ref string str)
        {
            return new StringNoGC(ref str);
        }
        public void Free()
        {
            unsafe
            {
                if (nofree || ptr == null)
                {
                    maxlen = 0;
                    ptr = null;
                }
                else
                {
                    UnsafePtrTool.FreeNoTemp(ptr);
                    maxlen = 0;
                    ptr = null;

                }
            }
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public void GetString(ref string refstr)
        {
            unsafe
            {
                if (ptr == null)
                    refstr = null;
                refstr = UnsafePtrTool.FromPtrUnsafe<string>(ptr);
            }
        }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]

        public string ToStringNoGC()
        {
            unsafe
            {
                if (ptr == null)
                    return null;

                return UnsafePtrTool.FromPtrUnsafe<string>(ptr);
            }
        }
        public override string ToString()
        {
            unsafe
            {
                if (ptr == null)
                    return "<null>";
                return new string(CharPtr, 0, Length);
            }
        }

    }

}
